/**
 expr ::= expr + term
 |   expr - term
 |   term

 term ::= term * factor
 |   term / factor
 |   factor

 factor ::= ( expr )
 |   NUM
 */

interface Token {
    toString(): string
}

class NumToken implements Token {
    value: number;
    constructor(value: string | number) {
        this.value = Number(value);
    }
}

class AddToken implements Token {
}

class MinToken implements Token {
}

function tokenScanner(str: string): Token[] {
    const NUM = '(\\d+)';
    const ADD = '(\\+)';
    const MIN = '(\\-)';
    const WS = '(\\S)';
    let re = RegExp(`${NUM}|${ADD}|${MIN}|${WS}`, 'g');
    let tokens: Token[] = [];
    let arr;
    while ((arr = re.exec(str)) !== null) {
        if (arr[1]) {
            tokens.push(new NumToken(arr[1]))
        } else if (arr[2]) {
            tokens.push(new AddToken())
        } else if (arr[3]) {
            tokens.push(new MinToken())
        } else if (arr[4]) {
        } else {
            throw new Error('invalid token');
        }
    }
    return tokens;
}

let tokens = tokenScanner('1 + 1 + 2');
console.dir(tokens);
